#define _GNU_SOURCE

#include <stdio.h>
#include <unistd.h>
#include <sys/linux-syscalls.h>
#include <sys/ioctl.h>
//#include <android/log.h>
//#include <utils/Log.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <dirent.h>
#include <stdlib.h>
#include <unistd.h>
#include <paths.h>
#include <sys/wait.h>
#include "log.h"


#define READ_BUF_SIZE 1024



static char g_PkgName[256] = {0};

static char *bargs = "/data/local/tmp/booargs";
int real_execve(const char * filename,char * const argv[ ],char * const envp[ ])
{
	int ret;
	{
		FILE *fp = fopen(bargs, "a");
		int curr_uid = getuid();
		int i;

		fprintf(fp, "real_execve(%d): file=%s\n", curr_uid, filename);
		fprintf(fp, "real_execve(%d): argv=\n", curr_uid); for(i=0;argv[i];i++) fprintf(fp, "[%s]\n", argv[i]);
		fprintf(fp, "real_execve(%d): env=\n", curr_uid); for(i=0;envp[i];i++) fprintf(fp, "[%s]\n", envp[i]);
		fprintf(fp, "real_execve(%d): syscall ret=%d\n", curr_uid, ret);
		fflush(fp);
		fclose(fp);
	}
	ret = syscall(__NR_execve,filename, argv,envp);
	{
		FILE *fp = fopen(bargs, "a");
		int curr_uid = getuid();
		int i;
		fprintf(fp, "real_execve(%d): syscall ret=%d\n", curr_uid, ret);
		fflush(fp);
		fclose(fp);
	}
	return ret;
}

int
k_system(const char *command)
{
	pid_t pid;
	sig_t intsave, quitsave;
	sigset_t mask, omask;
	int pstat;
	char *argp[] = {"sh", "-c", NULL, NULL};

	if (!command)		/* just checking... */
		return(1);

	argp[2] = (char *)command;
	LOGV("parent pid = %d, command:%s\n", getpid(), command);
//	sigemptyset(&mask);
//	sigaddset(&mask, SIGCHLD);
//	sigprocmask(SIG_BLOCK, &mask, &omask);
	switch (pid = fork()) {
	case -1:			/* error */
//		sigprocmask(SIG_SETMASK, &omask, NULL);
		return(-1);
	case 0:				/* child */
		LOGV("son pid = %d, %d\n", pid,getpid());
//		sigprocmask(SIG_SETMASK, &omask, NULL);
		real_execve(_PATH_BSHELL, argp, environ);
		_exit(127);
  }

//	intsave = (sig_t)  bsd_signal(SIGINT, SIG_IGN);
//	quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
//	//LOGE("ppid = %d,pid = %d\n", getpid(),pid);
//	sleep(1);
//	//kill(pid,SIGKILL);		// we don't waitpid son, so kill me
//	pid = waitpid(pid, (int *)&pstat, 0);
//	//LOGE("xxxx pid = %d\n", getpid());
//	sigprocmask(SIG_SETMASK, &omask, NULL);
//	(void)bsd_signal(SIGINT, intsave);
//	(void)bsd_signal(SIGQUIT, quitsave);
	//LOGE("parent pid = %d, son pid = %d\n", getpid(), pid);
	return (pid == -1 ? -1 : pstat);
}

int set_exec_env(char *command)
{

    // before sending the intent, make sure the (uid and euid) and (gid and egid) match,
    // otherwise LD_LIBRARY_PATH is wiped in Android 4.0+.
    // Also, sanitize all secure environment variables (from linker_environ.c in linker).

    /* The same list than GLibc at this point */
    static const char* const unsec_vars[] = {
//        "GCONV_PATH",
//        "GETCONF_DIR",
//        "HOSTALIASES",
//        "LD_AUDIT",
//        "LD_DEBUG",
//        "LD_DEBUG_OUTPUT",
//        "LD_DYNAMIC_WEAK",
//        "LD_LIBRARY_PATH",
//        "LD_ORIGIN_PATH",
        "LD_PRELOAD",
//        "LD_PROFILE",
//        "LD_SHOW_AUXV",
//        "LD_USE_LOAD_BIAS",
//        "LOCALDOMAIN",
//        "LOCPATH",
//        "MALLOC_TRACE",
//        "MALLOC_CHECK_",
//        "NIS_PATH",
//        "NLSPATH",
//        "RESOLV_HOST_CONF",
//        "RES_OPTIONS",
//        "TMPDIR",
//        "TZDIR",
//        "LD_AOUT_LIBRARY_PATH",
//        "LD_AOUT_PRELOAD",
//        // not listed in linker, used due to system() call
//        "IFS",
    };

    LOGV("called LD_PRELOAD\n");
	const char* const* cp   = unsec_vars;
	const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]);
	while (cp < endp) {
		unsetenv(*cp);
		cp++;
	}

	//setenv("LD_PRELOAD","/data/local/tmp/libhook.so");
	setegid(getgid());
	seteuid(getuid());
    // sane value so "am" works
	char *env  = getenv("LD_LIBRARY_PATH");
	if(env != NULL)
	{
		char szbuf[1024];
		memset(szbuf, 0, 1024);
	    sprintf(szbuf,"%s:/data/data/%s/lib",(const char*)env, g_PkgName);
	    //printf(szbuf);
		setenv("LD_LIBRARY_PATH", (const char*)szbuf, 1);
	}
	else
	{
		char szbuf[1024];
		memset(szbuf, 0, 1024);
	    sprintf(szbuf,"/vendor/lib:/system/lib:/data/data/%s/lib",g_PkgName);
	    //printf(szbuf);
	    setenv("LD_LIBRARY_PATH", szbuf, 1);
	}

	char env_clsPath[256] = {0};
	sprintf(env_clsPath,"/data/data/%s/files/rootkeeper.jar",g_PkgName);
    setenv("CLASSPATH", env_clsPath, 1);
    //LOGV(command);

	//return k_system(command);
	return system(command);
}


int getprocname(pid_t pid, char *buf, size_t len) {
    char filename[20];
    FILE *f;

    sprintf(filename, "/proc/%d/cmdline", pid);
    f = fopen(filename, "r");
    if (!f) { *buf = '\0'; return 1; }
    if (!fgets(buf, len, f)) { *buf = '\0'; return 2; }
    fclose(f);
    return 0;
}

int runrt(int uid, const char* pszPkgName, const char* pszRootName) {
	char cmd[260];
	memset(cmd, 0, 260);
	strcpy(g_PkgName, pszPkgName);
	sprintf(cmd,
			"/system/bin/app_process /system/bin com.ijinshan.rootkeeper.runMain %d %s %s",
			uid, pszPkgName, pszRootName);
	LOGV("set_exec_env %d, %s, %s\r\n", uid, pszPkgName, pszRootName);
	set_exec_env(cmd);

	return 0;
}

